/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2009，所有权利保留。
 * 
 * 项目名：	rumba-widget2
 * 文件名：	RLabeledComposite.java
 * 模块说明：	
 * 修改历史：
 * Feb 2, 2009 - lxm - 创建。
 */
package com.hd123.rumba.gwt.widget2.client.form;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.HasBlurHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyDownHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
import com.google.gwt.event.dom.client.HasKeyUpHandlers;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasFocus;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.SourcesFocusEvents;
import com.google.gwt.user.client.ui.SourcesKeyboardEvents;
import com.hd123.rumba.gwt.widget2.client.misc.RTextAlign;

/**
 * 具有标签的界面部件基类。
 * <p>
 * 
 * <b>控件元素结构</b><br>
 * div class=rb-Labeled<br>
 * ..div class=label<br>
 * ..?
 * <p>
 * 
 * <b>CSS Style Rules</b> <ol type=disc>
 * <li>.rb-Labeled {}</li>
 * <li>.rb-Labeled .label {}</li>
 * <li>.rb-Labeled .label-disabled {}</li> </ol>
 * 
 * @author lxm
 * 
 */
@SuppressWarnings("deprecation")
public class RLabeledBox extends Composite implements HasFocus, Focusable, HasAllFocusHandlers,
    HasAllKeyHandlers, WithRequired, RValidatable {

  private static final String STYLENAME_DEFAULT = "rb-Labeled";
  private static final String LABELWIDTH_DEFAULT = "80px";
  private static final String LABEL_STYLENAME = "label";

  /**
   * 创建对象实例。
   */
  public RLabeledBox() {
    super();
    drawSelf();
  }

  /**
   * 创建对象实例。
   * 
   * @param field
   *          指定所包含的表单域对象。
   */
  public RLabeledBox(HasRFieldCaption field) {
    this();
    setField(field);
  }

  private FlowPanel pnl;
  private RLabel label;
  private HasRFieldCaption field;

  /** 标签部分的显示宽度。 */
  public String getLabelWidth() {
    return DOM.getStyleAttribute(label.getElement(), "width");
  }

  /** 标签部分的显示宽度。 */
  public void setLabelWidth(String width) {
    DOM.setStyleAttribute(label.getElement(), "width", width);
  }

  /** 标签部分是否可见。 */
  public boolean isLabelVisible() {
    return label.isVisible();
  }

  /** 标签部分是否可见。 */
  public void setLabelVisible(boolean visible) {
    label.setVisible(visible);
  }

  /** 标签的对齐方式。 */
  public RTextAlign getLabelAlign() {
    return RTextAlign.valueOf(DOM.getStyleAttribute(label.getElement(), "textAlign"));
  }

  /** 标签的对齐方式。 */
  public void setLabelAlign(RTextAlign labelAlign) {
    String s = labelAlign == null ? null : labelAlign.getStyleText();
    DOM.setStyleAttribute(label.getElement(), "textAlign", s == null ? "" : s);
  }

  /**
   * 取得标签部分的元素。
   * 
   * @return
   */
  public Element getLabelElement() {
    return label.getElement();
  }

  /**
   * 取得当前的表单域控件对象。
   * 
   * @return
   */
  public HasRFieldCaption getField() {
    return field;
  }

  /**
   * 设置表单域控件对象。
   * 
   * @param field
   */
  public void setField(HasRFieldCaption field) {
    if (field != null && field.asWidget() == null)
      throw new RuntimeException("HasRFieldCaption.asWidget()方法禁止返回null值。");

    if (this.field != null) {
      this.field.removeFieldCaptionListener();
      pnl.remove(this.field.asWidget());
    }

    this.field = field;

    if (this.field != null) {
      pnl.add(this.field.asWidget());
      this.field.setFieldCaptionListener(new Listener_field());
    }

    refresh();
  }

  public int getTabIndex() {
    if (field instanceof Focusable)
      return ((Focusable) field).getTabIndex();
    else
      return 0;
  }

  public void setTabIndex(int index) {
    if (field instanceof Focusable)
      ((Focusable) field).setTabIndex(index);
  }

  public void setAccessKey(char key) {
    if (field instanceof Focusable)
      ((Focusable) field).setAccessKey(key);
  }

  public void setFocus(boolean focused) {
    if (field instanceof Focusable)
      ((Focusable) field).setFocus(focused);
  }

  /**
   * @deprecated 请用{@link #addFocusHandler}和
   *             {@link #addBlurHandler}代替
   */
  @Deprecated
  public void addFocusListener(FocusListener listener) {
    if (field instanceof SourcesFocusEvents)
      ((SourcesFocusEvents) field).addFocusListener(listener);
  }

  /**
   * @deprecated 请用{@link #addFocusHandler}和
   *             {@link #addBlurHandler}返回的
   *             {@link HandlerRegistration#removeHandler}代替
   */
  @Deprecated
  public void removeFocusListener(FocusListener listener) {
    if (field instanceof SourcesFocusEvents)
      ((SourcesFocusEvents) field).removeFocusListener(listener);
  }

  public HandlerRegistration addFocusHandler(FocusHandler handler) {
    if (field instanceof HasFocusHandlers)
      return ((HasFocusHandlers) field).addFocusHandler(handler);
    else
      return null;
  }

  public HandlerRegistration addBlurHandler(BlurHandler handler) {
    if (field instanceof HasBlurHandlers)
      return ((HasBlurHandlers) field).addBlurHandler(handler);
    else
      return null;
  }

  /**
   * @deprecated 请用{@link #addKeyUpHandler}、
   *             {@link #addKeyDownHandler}和
   *             {@link #addKeyPressHandler} 代替
   */
  @Deprecated
  public void addKeyboardListener(KeyboardListener listener) {
    if (field instanceof SourcesKeyboardEvents)
      ((SourcesKeyboardEvents) field).addKeyboardListener(listener);
  }

  /**
   * @deprecated 请用{@link #addKeyUpHandler}、
   *             {@link #addKeyDownHandler}和
   *             {@link #addKeyPressHandler}返回的
   *             {@link HandlerRegistration#removeHandler}代替
   */
  @Deprecated
  public void removeKeyboardListener(KeyboardListener listener) {
    if (field instanceof SourcesKeyboardEvents)
      ((SourcesKeyboardEvents) field).removeKeyboardListener(listener);
  }

  public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
    if (field instanceof HasKeyDownHandlers)
      return ((HasKeyDownHandlers) field).addKeyDownHandler(handler);
    else
      return null;
  }

  public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
    if (field instanceof HasKeyUpHandlers)
      return ((HasKeyUpHandlers) field).addKeyUpHandler(handler);
    else
      return null;
  }

  public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
    if (field instanceof HasKeyPressHandlers)
      return ((HasKeyPressHandlers) field).addKeyPressHandler(handler);
    else
      return null;
  }

  public boolean isRequired() {
    if (field instanceof WithRequired)
      return ((WithRequired) field).isRequired();
    else
      return false;
  }

  public void setRequired(boolean required) {
    if (field instanceof WithRequired)
      ((WithRequired) field).setRequired(required);
  }

  public void clearValidResults() {
    if (field instanceof RValidatable)
      ((RValidatable) field).clearValidResults();
  }

  public boolean isValid() {
    if (field instanceof RValidatable)
      return ((RValidatable) field).isValid();
    else
      return true;
  }

  public List getInvalidMessages() {
    if (field instanceof RValidatable)
      return ((RValidatable) field).getInvalidMessages();
    else
      return new ArrayList();
  }

  public boolean validate() {
    if (!isVisible())
      return true;

    if (field instanceof RValidatable)
      return ((RValidatable) field).validate();
    else
      return true;
  }

  private void drawSelf() {
    pnl = new FlowPanel();

    label = new RLabel();
    label.setStyleName(LABEL_STYLENAME);
    setLabelWidth(LABELWIDTH_DEFAULT);
    pnl.add(label);

    initWidget(pnl);
    setStyleName(STYLENAME_DEFAULT);
    sinkEvents(Event.ONCLICK);
  }

  private void refresh() {
    refreshInner();
    refreshEnabled();
  }

  private void refreshInner() {
    StringBuffer sb = new StringBuffer();
    if (field != null) {
      if (field.getFieldCaption() != null)
        sb.append(field.getFieldCaption());
      if (field.isRequired())
        sb.append("<font color=red>*</font>");
    }
    label.setHTML(sb.toString());
  }

  private void refreshEnabled() {
    boolean disabled = field != null && !field.isEnabled();

    String styleName = LABEL_STYLENAME;
    if (disabled)
      styleName += " " + LABEL_STYLENAME + "-disabled";
    label.setStyleName(styleName);

    if (disabled)
      DOM.setElementAttribute(label.getElement(), "disabled", "true");
    else
      DOM.removeElementAttribute(label.getElement(), "disabled");
  }

  private class Listener_field implements RFieldCaptionListener {
    public void onChange(HasRFieldCaption sender) {
      refresh();
    }
  }

  private class RLabel extends HTML {

    public RLabel() {
      super();
      sinkEvents(Event.ONCLICK);
    }

    public void onBrowserEvent(Event event) {
      super.onBrowserEvent(event);

      if (DOM.eventGetType(event) == Event.ONCLICK) {
        if (field != null && field instanceof Focusable)
          ((Focusable) field).setFocus(true);
      }
    }
  }

}
